package org.fixies.factory;

import org.fixies.resource.Initializer;
import org.fixies.utils.PropertyManager;
import org.fixies.utils.UnexpectedProblemException;


/**
 * 汎用ファクトリクラス<br/>
 * <p/>
 * キー「org.fixies.factory.GenericFactory.implementer」=値「クラス名」で具象クラスを差し替えできる。
 *
 * @author Kawasaki
 */
public final class GenericFactory {

    /**
     * 実装クラス名キー
     */
    private static final String IMPLEMENTER_CLASS_NAME_KEY = GenericFactory.class.getName() + ".implementer";

    private static final String DEFAULT_IMPLEMENTER_CLASS_NAME = DefaultFactory.class.getName();

    /**
     * シングルトンインスタンス
     */
    private static Factory soloInstance__;

    /**
     * デフォルトコンストラクタ
     */
    private GenericFactory() {
    }

    static {
        initialize();
    }

    /**
     * インスタンスを取得する
     *
     * @param key キー
     * @return インスタンス
     */
    public static Object getInstance(String key) {
        return soloInstance__.getInstance(key);
    }

    /**
     * 再初期化を行う。
     */
    public static synchronized void reInitialize() {
        initialize();
    }

    /**
     * 初期化を行う。
     */
    private static void initialize() {

        String className =
                PropertyManager.getProperty(
                        IMPLEMENTER_CLASS_NAME_KEY,
                        DEFAULT_IMPLEMENTER_CLASS_NAME);

        Factory implementer = null;
        try {
            implementer = (Factory) Class.forName(className).newInstance();
            implementer.initialize();
        } catch (Exception e) {
            throw new UnexpectedProblemException(e, "Can't get GenericFactory instance. class name=", className, "]");
        }
        setInstance(implementer);
    }

    private static synchronized void setInstance(Factory implementer) {
        soloInstance__ = implementer;
    }

    /**
     * ファクトリインタフェース
     */
    public interface Factory extends Initializer {

        /**
         * インスタンスを取得する
         *
         * @param key キー
         * @return インスタンス
         */
        Object getInstance(String key);
    }
}
